﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ReflectionAndMetadata
{
    class AdvancedThreading
    {
        public static void Show()
        {
            // 在电脑中只允许一个程序运行，不能多开
            // Naming a Mutex makes it available computer-write.Use a name that's unique to your computer and application
            using var mutex = new Mutex(true, @"Global\oreilly.com OneAtATimeDemo");

            // Wait a few seconds if contended in case another instance of the program is still in the process of shutting down.
            if (!mutex.WaitOne(TimeSpan.FromSeconds(3), false))
            {
                Console.WriteLine("Another instance of the app is running ,Bye!");
                Console.ReadKey();
                return;
            }
            try
            {
                RunProgram();
            }
            finally
            {
                mutex.ReleaseMutex();
            }

            void RunProgram()
            {
                Console.WriteLine("Running. Press Enter to exit");
                Console.ReadLine();
            }
        }

    }
    class User { }
    static class UserCache
    {
        static Dictionary<int, User> _users = new Dictionary<int, User>();
        internal static User GetUser(int id)
        {
            User u = null;
            lock (_users)
                if (_users.TryGetValue(id, out u))
                    return u;
            u = RetrieveUser(id);
            lock (_users) _users[id] = u;
            return u;
        }

        static User RetrieveUser(int id)
        {
            return new User();
        }
    }
    static class UserCacheTask
    {
        static Dictionary<int, Task<User>> _userTasks = new Dictionary<int, Task<User>>();

        internal static Task<User> GetUserAsync(int id)
        {
            lock (_userTasks)
                if (_userTasks.TryGetValue(id, out var userTask))
                    return userTask;
                else
                    return _userTasks[id] = Task.Run(() => RetrieveUser(id));
        }

        static User RetrieveUser(int id)
        {
            return new User();
        }
    }
}
